﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;

namespace DidaManager.Native.SerialPort
{
    public class SerialPortConfig
    {
        public Dictionary<string, string> m_dictSerialNames; // 串口名称字典(用于获取com号)

        // Win32 API 声明
        [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetupDiGetClassDevs(ref Guid classGuid, string enumerator, IntPtr hwndParent, uint flags);

        [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool SetupDiEnumDeviceInfo(IntPtr deviceInfoSet, uint memberIndex, ref SP_DEVINFO_DATA deviceInfoData);

        [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool SetupDiGetDeviceRegistryProperty(IntPtr deviceInfoSet, ref SP_DEVINFO_DATA deviceInfoData, uint property, out uint propertyRegDataType, StringBuilder propertyBuffer, uint propertyBufferSize, out uint requiredSize);

        [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet);

        // 常量定义
        private const uint DIGCF_PRESENT = 0x00000002;
        private const uint SPDRP_FRIENDLYNAME = 0x0000000C;
        private const uint SPDRP_DEVICEDESC = 0x00000000;

        // GUID for Ports (COM & LPT ports)
        private static readonly Guid GUID_DEVCLASS_PORTS = new Guid("4D36E978-E325-11CE-BFC1-08002BE10318");

        [StructLayout(LayoutKind.Sequential)]
        private struct SP_DEVINFO_DATA
        {
            public uint cbSize;
            public Guid classGuid;
            public uint devInst;
            public IntPtr reserved;
        }

        public SerialPortConfig()
        {
            m_dictSerialNames = new Dictionary<string, string>();
            InitDevicePortName();
        }

        /// <summary>
        /// 初始化设备端口名称
        /// </summary>
        private void InitDevicePortName()
        {
            m_dictSerialNames.Clear();
            
            try
            {
                // 方法1：尝试使用Win32 API获取串口信息
                if (TryGetPortsWithWin32Api())
                {
                    return;
                }
            }
            catch (Exception ex)
            {
                // 如果Win32 API失败，记录错误并尝试备用方法
                System.Diagnostics.Debug.WriteLine($"Win32 API方法失败: {ex.Message}");
            }

            try
            {
                // 方法2：使用注册表获取串口信息
                if (TryGetPortsWithRegistry())
                {
                    return;
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"注册表方法失败: {ex.Message}");
            }

            // 方法3：最简单的备用方法，只获取端口名
            GetPortsWithSimpleMethod();
        }

        /// <summary>
        /// 使用Win32 API获取串口信息
        /// </summary>
        private bool TryGetPortsWithWin32Api()
        {
            IntPtr deviceInfoSet = IntPtr.Zero;
            try
            {
                            Guid guid = GUID_DEVCLASS_PORTS;
            deviceInfoSet = SetupDiGetClassDevs(ref guid, null!, IntPtr.Zero, DIGCF_PRESENT);
                
                if (deviceInfoSet == IntPtr.Zero || deviceInfoSet.ToInt64() == -1)
                {
                    return false;
                }

                SP_DEVINFO_DATA deviceInfoData = new SP_DEVINFO_DATA();
                deviceInfoData.cbSize = (uint)Marshal.SizeOf(deviceInfoData);

                uint memberIndex = 0;
                while (SetupDiEnumDeviceInfo(deviceInfoSet, memberIndex, ref deviceInfoData))
                {
                    StringBuilder friendlyName = new StringBuilder(256);
                    uint propertyRegDataType;
                    uint requiredSize;

                    if (SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref deviceInfoData, SPDRP_FRIENDLYNAME, 
                        out propertyRegDataType, friendlyName, (uint)friendlyName.Capacity, out requiredSize))
                    {
                        string deviceName = friendlyName.ToString();

                        Match match = Regex.Match(deviceName, @"COM\d+", RegexOptions.IgnoreCase);
                        if (match.Success)
                        {
                            string portName = match.Value;
                            if (!string.IsNullOrEmpty(portName))
                            {
                                string displayName = portName + "    " + RemoveParenthesesAtEnd(deviceName);
                                if (!m_dictSerialNames.ContainsKey(displayName))
                                {
                                    m_dictSerialNames.Add(displayName, portName);
                                }
                            }
                        }

                    }
                    memberIndex++;
                }

                return m_dictSerialNames.Count > 0;
            }
            finally
            {
                if (deviceInfoSet != IntPtr.Zero && deviceInfoSet.ToInt64() != -1)
                {
                    SetupDiDestroyDeviceInfoList(deviceInfoSet);
                }
            }
        }

        /// <summary>
        /// 使用注册表获取串口信息
        /// </summary>
        private bool TryGetPortsWithRegistry()
        {
            try
            {
                // 从注册表获取串口列表
                using (RegistryKey? key = Registry.LocalMachine.OpenSubKey(@"HARDWARE\DEVICEMAP\SERIALCOMM"))
                {
                    if (key != null)
                    {
                        string[] valueNames = key.GetValueNames();
                        foreach (string valueName in valueNames)
                        {
                                                string? portName = key.GetValue(valueName)?.ToString();
                    if (!string.IsNullOrEmpty(portName))
                            {
                                // 尝试获取设备描述
                                string deviceDescription = GetDeviceDescriptionFromRegistry(portName);
                                string displayName = string.IsNullOrEmpty(deviceDescription) 
                                    ? portName 
                                    : portName + "    " + deviceDescription;
                                
                                if (!m_dictSerialNames.ContainsKey(displayName))
                                {
                                    m_dictSerialNames.Add(displayName, portName);
                                }
                            }
                        }
                    }
                }

                return m_dictSerialNames.Count > 0;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 从注册表获取设备描述
        /// </summary>
        private string GetDeviceDescriptionFromRegistry(string portName)
        {
            try
            {
                // 在设备管理器相关的注册表位置查找设备信息
                using (RegistryKey? key = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Enum"))
                {
                    if (key != null)
                    {
                        return SearchForPortDescription(key, portName);
                    }
                }
            }
            catch
            {
                // 忽略错误，返回空字符串
            }
            return string.Empty;
        }

        /// <summary>
        /// 递归搜索端口描述
        /// </summary>
        private string SearchForPortDescription(RegistryKey parentKey, string portName)
        {
            try
            {
                            foreach (string subKeyName in parentKey.GetSubKeyNames())
            {
                using (RegistryKey? subKey = parentKey.OpenSubKey(subKeyName))
                    {
                        if (subKey != null)
                        {
                                                    // 检查当前键的设备参数
                        using (RegistryKey? deviceParamsKey = subKey.OpenSubKey("Device Parameters"))
                            {
                                if (deviceParamsKey != null)
                                {
                                                                string? portNameValue = deviceParamsKey.GetValue("PortName")?.ToString();
                            if (portName.Equals(portNameValue, StringComparison.OrdinalIgnoreCase))
                            {
                                string? friendlyName = subKey.GetValue("FriendlyName")?.ToString();
                                        if (!string.IsNullOrEmpty(friendlyName))
                                        {
                                            return RemoveParenthesesAtEnd(friendlyName);
                                        }
                                    }
                                }
                            }

                            // 递归搜索子键
                            string result = SearchForPortDescription(subKey, portName);
                            if (!string.IsNullOrEmpty(result))
                            {
                                return result;
                            }
                        }
                    }
                }
            }
            catch
            {
                // 忽略访问被拒绝等错误
            }
            return string.Empty;
        }

        /// <summary>
        /// 最简单的获取串口方法（备用）
        /// </summary>
        private void GetPortsWithSimpleMethod()
        {
            try
            {
                string[] ports = System.IO.Ports.SerialPort.GetPortNames();
                foreach (string port in ports)
                {
                    if (!m_dictSerialNames.ContainsKey(port))
                    {
                        m_dictSerialNames.Add(port, port);
                    }
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"简单方法也失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 从设备名称中提取端口名称
        /// </summary>
        private string ExtractPortName(string deviceName)
        {
            if (string.IsNullOrEmpty(deviceName))
                return string.Empty;

            // 查找括号中的COM端口号
            int startIndex = deviceName.LastIndexOf('(');
            int endIndex = deviceName.LastIndexOf(')');
            
            if (startIndex >= 0 && endIndex > startIndex)
            {
                string portPart = deviceName.Substring(startIndex + 1, endIndex - startIndex - 1);
                if (portPart.StartsWith("COM", StringComparison.OrdinalIgnoreCase))
                {
                    return portPart.ToUpper();
                }
            }

            return string.Empty;
        }

        /// <summary>
        /// 移除字符串末尾的括号及其内容
        /// </summary>
        /// <param name="input">输入字符串</param>
        /// <returns>移除括号及其内容后的字符串</returns>
        public string RemoveParenthesesAtEnd(string input)
        {
            // 寻找最后一个左括号的位置  
            int lastParenIndex = input.LastIndexOf('(');

            if (lastParenIndex != -1)
            {
                // 去掉括号及其内容  
                return input.Substring(0, lastParenIndex).Trim();
            }

            return input; // 如果找不到括号，则返回原始字符串  
        }

        public string GetSerialPortValue(string key)
        {
            if (m_dictSerialNames.TryGetValue(key, out var value))
            {
                return value;
            }
            return string.Empty;
        }
    }
}
